package me.flyray.bsin.server.impl;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import me.flyray.bsin.facade.service.ElasticsearchService;
import me.flyray.bsin.server.config.ElasticSearchConfig;
import me.flyray.bsin.server.domain.MedicalKnowledgeBase;
import me.flyray.bsin.server.utils.BsinServiceContext;
import me.flyray.bsin.server.utils.RespBodyHandler;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;


public class ElasticsearchServiceImpl implements ElasticsearchService {

    @Autowired
    private RestHighLevelClient client;

    /**
     * jackson的objectMapper
     */
    ObjectMapper objectMapper=new ObjectMapper();

    /**
     * 创建索引
     */
    @Override
    public Map<String, Object> createIndex(Map<String, Object> requestMap) throws IOException {
        String indexName = (String)requestMap.get("indexName");
        // 1、创建索引请求
        CreateIndexRequest request = new CreateIndexRequest(indexName);
        // 2、客户端client执行请求 IndicesClient对象，请求后获得响应
        CreateIndexResponse createIndexResponse = null;
        createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
        System.out.println(createIndexResponse);
        return RespBodyHandler.RespBodyDto();
    }

    /**
     * 删除索引
     */
    @Override
    public Map<String, Object> deleteIndex(Map<String, Object> requestMap) throws IOException {
        String indexName = (String)requestMap.get("indexName");
        DeleteIndexRequest request = new DeleteIndexRequest(indexName);
        AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
        System.out.println(delete);
        return RespBodyHandler.RespBodyDto();
    }

    /**
     * 添加医疗知识库 文档
     */
    @Override
    public Map<String, Object> addDocument(Map<String, Object> requestMap) throws  IOException {
        MedicalKnowledgeBase medicalKnowledgeBase = BsinServiceContext.getReqBodyDto(MedicalKnowledgeBase.class, requestMap);
        String indexName = (String)requestMap.get("indexName");
        //指定索引和id
        IndexRequest request=new IndexRequest(indexName);
        request.id(medicalKnowledgeBase.getId());
        request.timeout("10s");

        //数据转为json格式
        String userString= objectMapper.writeValueAsString(medicalKnowledgeBase);
        request.source(userString, XContentType.JSON);

        //执行保存操作
        IndexResponse indexResponse=client.index(request, ElasticSearchConfig.COMMON_OPTIONS);

        System.out.println(indexResponse.toString());
        System.out.println(indexResponse.status());
        return RespBodyHandler.RespBodyDto();
    }

    /**
     * 查看医疗知识库文档详情详情
     */
    @Override
    public Map<String, Object> getDocument(Map<String, Object> requestMap) throws IOException {
        String indexName = (String)requestMap.get("indexName");
        String id = (String)requestMap.get("id");
        GetRequest getRequest = new GetRequest(indexName, id);
        GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
        System.out.println(getResponse.getSourceAsString());
        System.out.println(getResponse);
        return RespBodyHandler.setRespBodyDto(getResponse.getSourceAsString());
    }

    /**
     * 删除医疗知识库文档
     */
    @Override
    public Map<String, Object> deleteDocument(Map<String, Object> requestMap) throws IOException {
        String indexName = (String)requestMap.get("indexName");
        String id = (String)requestMap.get("id");

        //指定索引和id
        DeleteRequest request=new DeleteRequest(indexName,id);
        request.timeout("1s");

        //执行保存操作
        DeleteResponse indexResponse=client.delete(request,ElasticSearchConfig.COMMON_OPTIONS);
        System.out.println(indexResponse.status());
        return RespBodyHandler.RespBodyDto();
    }

    /**
     * 修改医疗知识库文档信息
     */
    @Override
    public Map<String, Object> updateDocument(Map<String, Object> requestMap) throws IOException {
        MedicalKnowledgeBase medicalKnowledgeBase = BsinServiceContext.getReqBodyDto(MedicalKnowledgeBase.class, requestMap);
        String indexName = (String)requestMap.get("indexName");
        // 创建更新请求
        UpdateRequest updateRequest = new UpdateRequest(indexName, medicalKnowledgeBase.getId());
        updateRequest.timeout("1s");
        String jsonString = JSON.toJSONString(medicalKnowledgeBase);
        updateRequest.doc(jsonString,XContentType.JSON);
        // 执行更新操作
        UpdateResponse updateResponse = client.update(updateRequest, RequestOptions.DEFAULT);
        System.out.println(updateResponse.status());
        return RespBodyHandler.RespBodyDto();
    }


    /**
     * 通过ik分词器，查询跟任务关键词相关医疗知识库文档
     */
    @Override
    public Map<String, Object> getDocumentListByKeyword(Map<String, Object> requestMap) throws IOException {
        String indexName = (String) requestMap.get("indexName");
        String keyword = (String) requestMap.get("keyword");

        // 创建检索请求
        SearchRequest searchRequest = new SearchRequest();
        // 指定索引
        searchRequest.indices(indexName);

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();// 创建查询

        // 编写query match查询条件，用ik_smart 对note字段进行分词，分词之间的关系为 or
        // Operator.AND：表示将查询条件分词后，必须同时存在，效果等同于match_phrase
        // Operator.OR：表示将查询条件分词后，只要中一个就行，默认值为OR
        // ik_smart : 会做最粗粒度的拆分（更加智能的拆分）

        /* 问题 查询条件分词 之后 精准查询 而不是模糊查询 */
        sourceBuilder.query(QueryBuilders.matchQuery("title", keyword).analyzer("ik_smart").operator(Operator.OR));

        // 编写聚合条件
        // AggregationBuilders.terms("ageAgg").field("age") 等同于group by , name值自定义，id为需要分组的key
//        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("tit").field("title").size(10);

        // 聚合条件绑定查查询语句中
//        sourceBuilder.aggregation(aggregationBuilder);
        System.out.println("查询语句：" + sourceBuilder.toString());

        // 查询语句放置到请求中
        searchRequest.source(sourceBuilder);

        // 执行查询请求
        SearchResponse searchResponse = client.search(searchRequest, ElasticSearchConfig.COMMON_OPTIONS);

        SearchHits hits = searchResponse.getHits();
        TotalHits totalHits = hits.getTotalHits();// 查询命中数
        System.out.println("命中数：" + totalHits);
        SearchHit[] searchHits = hits.getHits();// 查询结果

        System.out.println(Arrays.toString(searchHits));
        String s = Arrays.toString(searchHits);
        final List<SearchHit> searchHits1 = Arrays.asList(searchHits);
        return RespBodyHandler.setRespBodyDto(s);
    }

}
